#ifndef __CACHE_ENTRY__
#define __CACHE_ENTRY__

#ifdef __cplusplus 
extern "C" { 
#endif

#include <stdint.h>
#include "../../log.h"

#ifndef unlikely
#define unlikely(x)     __builtin_expect(!!(x),0)
#endif

struct CacheRegistry;
struct Segment;

struct Segment
{
	union{
		struct{
			uint64_t begin, end;	// segment begin and end
			uint64_t logic_pos;			// at pos the segment is stored
		};
		struct{
			uint64_t begin_pos, end_pos; // for segment on cache file
			int64_t reference;
		};
	};
};

typedef int (*cb_journal_free_t)(uint64_t pos_begin, uint64_t pos_end, void* data);

// create a new CacheRegistry
struct CacheRegistry* cache_create(cb_journal_free_t free_fun, void* data);

// insert a segment s, into the cache registry
// return 0 for success, <0 for failure
int cache_insert(struct CacheRegistry* cr, struct Segment* /*IN*/ s);

// look up in the cache registry for a segment [s->begin, s->end),
// return 0 for success, <0 for failure; s->pos and s->end will be set to proper value when succeeded
// users may need multiple inovcations for a single request, to iterate all the segments involved
// *iterator should be assigned to NULL when looking up the first segment involved
int cache_lookup(struct CacheRegistry* cr, struct Segment* /*IN*/ s, struct Segment* so, void** iterator);
int cache_lookup_multy(struct CacheRegistry* cr, struct Segment* /*IN*/ is, struct Segment* /*OUT*/ *os);
int cache_lookup_journal(struct CacheRegistry* cr, struct Segment* /*IN-OUT*/ s, uint64_t cache_size);
void debug_test_set_all_write_back(struct CacheRegistry* cr);
int cache_remove(struct CacheRegistry* cr, struct Segment* is);
int cache_clear_range(struct CacheRegistry* cr, uint64_t offset, uint32_t len);
int print_cache(struct CacheRegistry* cr);
uint64_t cache_count_coverage(struct CacheRegistry* cr);

// get the a segment of the cache registry for writing back
// return number of segments remained in the registry (>=0) for success, <0 for failure
int begin_write_back(struct CacheRegistry* cr, struct Segment* /*OUT*/ s);

// complete the write back operation, by removing the segment (returned by begin_write_back) from the cache
// return number of segments remained in the registry (>=0) for success, <0 for failure
int end_write_back(struct CacheRegistry* cr, struct Segment* /*IN*/ s);
void clear_all_iterm(struct CacheRegistry* cr);

// destroy a cache registry
void cache_destroy(struct CacheRegistry* cr);


#ifdef __cplusplus 
}
#endif

#endif
